package com.gupaoedu.spring.framework.beans.support;

import com.gupaoedu.spring.framework.beans.config.GPBeanDefinition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author fan
 * @version 1.0v
 * @Description TODO
 * @date 2021-01-03 19:38
 * @email 44867924@qq.com
 */
public class GPBeanDefinitionReader {

    /**
     * 读取properties的工具类 java自带
     */
    private Properties contextConfig = new Properties();

    /**
     * 要被注册到ioc容器中的类
     */
    List<String> registryBeanClasses = new ArrayList<>();

    public GPBeanDefinitionReader(String ... configLocations) {
        // configLocations　：　[“application.properties”]　这里是一个字符串数组
        doLoadConfig(configLocations[0]);
        // contextConfig : scanPackage -> com.gupaoedu.demo
        // contextConfig.getProperty("scanPackage")   ==== > scanPackage=com.gupaoedu.demo
        doSanner(contextConfig.getProperty("scanPackage"));
    }


    public Object getBean(Class beanClass){
        return getBean(beanClass.getName());
    }

    public Object getBean(String beanName){
        return null;
    }


    /**
     * 　加载Bean定义
     * registryBeanClasses：这里面是扫描到的所有类
     * @return
     */
    public List<GPBeanDefinition> loadBeanDefinitons() {

        //　装的是BeanDefinition实例　包含 factoryBeanName 类名小写　和　beanClassName　类的全限定名(包名加类名)
        List<GPBeanDefinition> result = new ArrayList<>();
        try {
            for (String className : registryBeanClasses) {
                // 通过反射得到对应的类
                Class<?> beanClass = Class.forName(className);
                // 判断是不是　接口
                if(beanClass.isInterface()){
                    continue;
                }
                // 添加到bean的集合中　　　　　　　　　　类名首字母小写　　　类名：DemoAction       全限定名： com.gupaoedu.demo.action.DemoAction　　　　　　　　
                result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()),beanClass.getName()));
                // 对接口的处理　　getInterfaces()：获得这个对象所实现的所有接口。
                for (Class<?> i : beanClass.getInterfaces()) {
                    result.add(doCreateBeanDefinition(i.getName(),beanClass.getName()));
                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }
        // 8+3 3个action 4个实现类　4个实现类对应的接口
        return result;
    }

    /**
     *　定义bean
     * @param factoryBeanName　这个是类名小写 demoAction
     * @param beanClassName　这个中包类+　类名（大写）　com.gupaoedu.demo.action.DemoAction
     * @return beanDefinition　实例
     */
    private GPBeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) {
        GPBeanDefinition beanDefinition = new GPBeanDefinition();
        beanDefinition.setFactoryBeanName(factoryBeanName);
        beanDefinition.setBeanClassName(beanClassName);
        return beanDefinition;
    }

    /**
     * 加载配置文件的值
     * @param contextConfigLocation　对应的配置文件的值　eg: <param-value>application.properties</param-value> 这个里面的值
     */
    private void doLoadConfig(String contextConfigLocation) {
        // 加载配置文件
        // 在classPath去找
        // 变成一个文件流
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation.replaceAll("classpath:",""));
        try {
            contextConfig.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

    /**
     * 扫描对应路径下所有的类
     * @param scanPackage　com.gupaoedu.demo　配置的路径　要扫描哪个路径下的类
     */
    private void doSanner(String scanPackage) {
        // 用正则，把点变成'/'
        // url : file:/D:/web_hello2/out/artifacts/web_hello2_war_exploded/WEB-INF/classes/com/gupaoedu/demo/
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
        // 把这个url变成一个文件
        //得到这个文件的路径
        // url.getFile : /D:/web_hello2/out/artifacts/web_hello2_war_exploded/WEB-INF/classes/com/gupaoedu/demo/
        File classPth = new File(url.getFile());
        // classPth.listFiles() 结果如下
        // 0: D:\web_hello2\out\artifacts\web_hello2_war_exploded\WEB-INF\classes\com\gupaoedu\demo\action
        // 1: D:\web_hello2\out\artifacts\web_hello2_war_exploded\WEB-INF\classes\com\gupaoedu\demo\service
        for (File file : classPth.listFiles()) {
            // 这里的file有文件，也有文件夹
            if (file.isDirectory()) {
                // file.getName() : action
                doSanner(scanPackage + "." + file.getName());
            } else {
                // 一个文件夹下面会有各种各样的文件 这里只要以.class结尾的文件
                // file : D:\web_hello2\out\artifacts\web_hello2_war_exploded\WEB-INF\classes\com\gupaoedu\demo\action\DemoAction.class
                if (!file.getName().endsWith(".class")) {
                    continue;
                }
                // 得到他的全类名 fileName:com.gupaoedu.demo.action.DemoAction
                String fileName = (scanPackage + "." + file.getName().replace(".class", ""));
                registryBeanClasses.add(fileName);
            }
        }
    }

    /**
     *  首字母小写
     */
    private String toLowerFirstCase(String simpleName) {
        char[] chars = simpleName.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }
}
